﻿//////////////////////////////////////////////////////////////////////////////
//
//  Copyright © 1998-2024 Glodon Company Limited.  All rights reserved.
//
//  Use of this software is subject to the terms of the Glodon license
//  agreement provided at the time of installation or download, or which
//  otherwise accompanies this software in either electronic or hard copy form.  
//
//////////////////////////////////////////////////////////////////////////////


#pragma once
#include "GnufItem.h"
#include "GnufButtonControl.h"

namespace gnuf {
    
    class BlockAppearanceSetting;
    class Button;
    class ButtonEx;
    class Toolbar;
    class ProgressItem;
    class Text;
    class NameValuePair;
    class QtBlock;
    class List;
    class Check;
    class CheckListButton;
    class LineEditComboBox;
    class TableRow;
    enum class EButtonDisplayStyle;

    class GNUF_BASE_EXPORT Block final
        : public ItemWith<QtBlock>
    {
        CANNOT_COPY_OR_ASSIGN(Block);
        
    public:
        enum class ELayoutType : std::uint8_t
        {
            eHBoxLayout,   ///< 水平布局
            eVBoxLayout,   ///< 垂直布局
            eGridLayoutByColumn,   ///< 网格布局，逐列填充
            eGridLayoutByRow     ///< 网格布局，逐行填充
        };

        static const EItemType Type;
        explicit Block(Toolbar *);
        explicit Block(NameValuePair*);
        // 支持Block嵌入到Table单元格中
        explicit Block(TableRow*);

        virtual ~Block();

        template<typename TItem>
        TItem* addItem()
        {
            static_assert(std::is_base_of<Item, TItem>::value, "typename just only inherit from Item");
            gcmp::OwnerPtr<TItem> item = NEW_AS_OWNER_PTR(TItem, this);
            TItem* ptr = item.get();
            m_contents.push_back(TransferOwnership(item));
            return ptr;
        }

        template<typename TItem>
        TItem* addItem(gcmp::OwnerPtr<TItem>&& item)
        {
            static_assert(std::is_base_of<Item, TItem>::value, "typename just only inherit from Item");
            TItem* ptr = item.get();
            m_contents.push_back(TransferOwnership(item));
            return ptr;
        }

        Item * addNameValuePair(const Info&, EItemType valueType, bool isTagNameType);

        bool hasContents() const { return !m_contents.empty(); }
        void clearContents();
        void dumpContents();

        void setRowAndColumnForGrid(int rowCount, int columnCount);
        int rowCountForGrid()const { return m_rowCount; }
        int columnCountForGrid()const { return m_columnCount; }

        void setLayoutType(ELayoutType layout) { m_layoutType = layout; }
        ELayoutType layoutType() const { return m_layoutType; }

        void setWantToSyncVisibilityWithChild(bool val) { m_wantToSyncVisibilityWithChild = val; }
        bool wantToSyncVisibilityWithChild() const { return m_wantToSyncVisibilityWithChild; }

        // 动态和删除
        int indexOf(const Item* item);
        void dumpItem(Item* item);
        bool removeItem(Item* pItem);

        template<typename TItem>
        TItem* insertItem(int index)
        {
            static_assert(std::is_base_of<Item, TItem>::value, "typename just only inherit from Item");
            gcmp::OwnerPtr<TItem> item = NEW_AS_OWNER_PTR(TItem, this);
            TItem* ptr = item.get();

            // maybe should display a debug warning rather than default behavior
            if (index < 0 || index >= m_contents.size())
            {
                m_contents.push_back(TransferOwnership(item));
            }
            else
            {
                auto itor = m_contents.begin();
                advance(itor, index);
                m_contents.insert(itor, TransferOwnership(item));
            }
            return ptr;
        }

        typedef std::list< gcmp::OwnerPtr<Item> > Contents;
        typedef std::vector< Item * > RawContents;
        const Contents & contents() const { return m_contents; }
        RawContents rawContents();

        void setWorkspace(const std::wstring &);
        const std::set<std::wstring> & workspace() const { return m_workspace; }

        void setCaption(const std::wstring & val) { m_caption = val; }
        const std::wstring& caption() const { return m_caption; }

        void setButtonDisplayStyle(EButtonDisplayStyle style);

        int index() const;

        struct BlockAppearanceSetting
        {
            /*
                                            Spacing between Controls
                                                    /
            +--------------------------------------/--------------+
            |                     Top Spacing     /               |
            |       +----------------------------o--------+       |
            |Left   |       | |       | |       | |       |  Right|
            |       |Control| |Control| |Control| |Control|       |
            |Spacing|       | |       | |       | |       |Spacing|
            |       +-------------------------------------+       |
            |                   Bottom Spacing                    |
            +-----------------------------------------------------+
            */
            BlockAppearanceSetting();
            int fixedWidth = 0;
            int leftSpacing = 0, topSpacing = 0, rightSpacing = 0, bottomSpacing = 0;
            int spacingBetweenControls = 0;
            int spacingShrink = 0;
        };

        inline const Block::BlockAppearanceSetting & blockAppearanceSetting() const {
            return m_blockAppearanceSetting;
        }
        Block::BlockAppearanceSetting & rBlockAppearanceSetting() {
            return m_blockAppearanceSetting;
        }

        void setBlockAppearanceSetting(const Block::BlockAppearanceSetting& setting) {
            m_blockAppearanceSetting = setting;
        }

        int fixedWidth(const bool wantToSubtractLeftAndRightSpacing = true) const;
        int leftSpacing() const;
        int topSpacing() const;
        int rightSpacing() const;
        int bottomSpacing() const;
        int spacingBetweenControls() const;

        /// \brief 设置嵌入表格的Block中的控件宽度占比系数;例如：控件1系数2，控件2系数为1，则宽度为2比1；
        bool setStretchFactor(Item* pItem, int factor);
        int stretchFactor(Item* pItem);

        void setSpacingBetweenControls(int);

        // 设置嵌入表格的Block的Button固定尺寸
        void setButtonFixedSizeAtCell(Item*, int w, int h);

        bool doesExpectToShow() const;
    protected:
        // Inherits from ItemWith...
        virtual void onChildHeightChanged(Item *, int) override;
        virtual void onDisconnectFromMyQtItem() override;
        virtual void onPostAppearanceSettingChanged() override;
        virtual void onPostVisibilityChanged() override;
        virtual void onChildVisibilityChanged(const Item*) override;
        virtual void onTableRowSelectionChanged(bool) override;

    private:
        bool isNoAnyContentVisbile() const;
    
        Block::Contents m_contents;
        Block::BlockAppearanceSetting m_blockAppearanceSetting;
        std::set<std::wstring> m_workspace;
        bool    m_wantToSyncVisibilityWithChild;
        ELayoutType m_layoutType;
        int m_rowCount, m_columnCount;

        std::wstring m_caption;
        std::map<Item*, int> m_stretchFactor; // Block 水平布局，控件宽度占比系数
    };
    
}
